# 导入函数库
from jqdata import *
from datetime import timedelta


# 初始化函数，设定基准等等
def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 输出内容到日志 log.info()
    log.info('初始函数开始运行且全局只运行一次')
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')

    ### 股票相关设定 ###
    # 股票类每笔交易时的手续费是：买入时佣金万分之三，卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.00015, close_commission=0.00015, min_commission=5),
                   type='stock')

    ## 运行函数（reference_security为运行时间的参考标的；传入的标的只做种类区分，因此传入'000300.XSHG'或'510300.XSHG'是一样的）

    # 开盘前，集合竞价后 运行
    run_daily(trade, time='14:50')


def trade(context):
    # 上一天龙虎榜股票
    board_stocks = bill_board_stock(context)
    # log.info("上一日龙虎榜股票" + str(board_stocks[:10]))
    # 净流出最多的10支票，如果持有，跑了
    tail_10 = board_stocks[-5:]
    # 先卖出股票腾仓位
    long_positions_dict = context.portfolio.long_positions
    for position in list(long_positions_dict.values()):
        if position.security in tail_10:
            order_target(position.security, 0)
            log.info("昨天龙虎榜资金流出太多，卖出=======" + position.security)
            continue
        # 止盈（30%） 止损（10%）
        if position.price < position.acc_avg_cost * 0.9:
            order_target(position.security, 0)
            log.info("止损（10%），卖出=======" + position.security)
        if position.price > position.acc_avg_cost * 1.3:
            order_target(position.security, 0)
            log.info("止盈（30%），卖出=======" + position.security)

        ma5 = get_bars(position.security, count=5, unit='1d', fields=['close'])['close'].mean()
        if position.price < ma5:
            order_target(position.security, 0)
            log.info("跌破5日线，卖出=======" + position.security)

    # 如果没有仓位了，今天不动了
    available_cash = context.portfolio.available_cash
    if available_cash < 3000:
        log.info("没钱了，今天不动了")
        return

    # 龙虎榜净流入靠前的票
    head_10 = board_stocks[:10]
    # 账户总资产（现金+股票市值）, 每次买入一只票最多5成仓
    buy_max_per_stock = round(context.portfolio.total_value * 0.5, 2)
    # 获取当前数据，主要是为了拿到开盘价
    current_data = get_current_data()

    # 循环处理每只备选票
    for stock in head_10:
        # 取得当前的现金
        cash = context.portfolio.available_cash
        if cash < 3000:
            log.info("没钱了，今天不继续买了")
            return
        # 获取ma均线
        ma5 = get_bars(stock, count=5, unit='1d', fields=['close'])['close'].mean()
        # 获取昨天的收盘价
        pre_close = attribute_history(stock, 1, '1d', ('close'))['close'][-1]
        # 最新价
        current_price = current_data[stock].last_price
        # 涨停价
        high_limit_price = current_data[stock].high_limit
        # 跌停价
        # low_limit_price = current_data[stock].low_limit
        # 如果没有涨停，买入
        if (current_price > ma5) and (current_price < high_limit_price) and (current_price > pre_close) and (
                context.portfolio.positions[stock].closeable_amount <= 0):
            # 用所有 cash 买入股票
            # order_value(stock, cash)
            # 用最多1/3仓位买入
            buy_cash = min(cash, buy_max_per_stock)
            order_value(stock, buy_cash)


def bill_board_stock(context):
    # 龙虎榜股票
    billboard = get_billboard_list(stock_list=None, end_date=(context.current_dt + timedelta(days=-1)), count=1)
    sorted_board = billboard.loc[billboard['direction'] == 'ALL'].sort_values(by='net_value', ascending=False)
    return list(sorted_board['code'])


